package ar.edu.unrn.lia.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;

import ar.edu.unrn.lia.model.Movimiento.TipoMovimiento;

@Entity
@Table(
        name="cuenta", uniqueConstraints =       @UniqueConstraint (columnNames={"codigo"})
    )
public class Cuenta extends BaseEntity implements Serializable {

	private static final long serialVersionUID = -533106217592044766L;

	private String nombre;
	private String codigo;
	private Integer numero;
	private List<Movimiento> movimientos = new ArrayList<Movimiento>(0);
	private String tipo;
	private boolean imputable;
	private Cliente cliente;
	private Double saldo = 0.0;
	private Estado estado = Estado.SALDADA;
	private Grupo grupo = Grupo.ACTIVO;
	private SubGrupo subGrupo = SubGrupo.CLIENTES;

	public Cuenta() {
		super();
	}

	public Cuenta(String nombre, String codigo, Grupo grupo, SubGrupo subGrupo,
			Integer numero, List<Movimiento> movimientos, String tipo,
			boolean imputable) {
		super();
		this.nombre = nombre;
		this.codigo = codigo;
		this.numero = numero;
		this.movimientos = movimientos;
		this.tipo = tipo;
		this.imputable = imputable;
	}

	@Transient
	public void establecerCodigo() {
		if (grupo != null && subGrupo != null && numero != null) {
			String sGrupo = String.format("%02d", grupo.value);
			String sSubGrupo = String.format("%02d", subGrupo.value);
			String sNumero = String.format("%03d", numero);
			this.setCodigo(sGrupo + sSubGrupo + sNumero);
		}
	}

	public enum Grupo {
		ACTIVO(1), PASIVO(2), INGRESO(3);

		private Integer value;

		private Grupo(Integer value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return String.valueOf(value);
		}

		public Integer getValue() {
			return this.value;
		}
	}

	@Enumerated
	@NotNull(message = "{name.notnull}")
	public Grupo getGrupo() {
		return grupo;
	}

	public void setGrupo(Grupo grupo) {
		this.grupo = grupo;
	}

	public enum SubGrupo {
		CAJA(1), CLIENTES(2);

		private Integer value;

		private SubGrupo(Integer value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return String.valueOf(value);
		}

		public Integer getValue() {
			return this.value;
		}
	}

	@Enumerated	
	public SubGrupo getSubGrupo() {
		return subGrupo;
	}

	public void setSubGrupo(SubGrupo subGrupo) {
		this.subGrupo = subGrupo;

	}

	public enum Estado {
		 SALDADA("Saldada"), SALDO_ACREEDOR("Saldo Acreedor"),SALDO_DEUDOR("Saldo Deudor ");

		private String value;

		private Estado(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	@Enumerated(EnumType.STRING)
	@NotNull(message = "{name.notnull}")
	public Estado getEstado() {
		return estado;
	}

	public void setEstado(Estado estado) {
		this.estado = estado;
	}

	@OneToOne(mappedBy = "cuenta", targetEntity = Cliente.class, fetch = FetchType.LAZY)
	public Cliente getCliente() {
		return cliente;
	}

	public void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	@Column(name = "saldo", precision = 15, scale = 3)
	@NotNull(message = "{name.notnull}")
	public Double getSaldo() {
		return saldo;
	}

	public void setSaldo(Double saldo) {
		this.saldo = saldo;
	}

	@Column(name = "nombre", length = 30)
	@NotNull(message = "{name.notnull}")
	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	@Column(name = "codigo", length = 20)
	@NotNull(message = "{name.notnull}")
	public String getCodigo() {
		return codigo;
	}

	public void setCodigo(String codigo) {
		this.codigo = codigo;
	}

	@Column(name = "numero")
	@NotNull(message = "{name.notnull}")
	public Integer getNumero() {
		return numero;
	}

	public void setNumero(Integer numero) {
		this.numero = numero;
	}

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "cuenta", fetch = FetchType.LAZY)
	@OrderBy("fecha DESC")
	public List<Movimiento> getMovimientos() {
		return movimientos;
	}

	public void setMovimientos(List<Movimiento> movimientos) {
		this.movimientos = movimientos;
	}

	@Column(name = "tipo", length = 30)
	public String getTipo() {
		return tipo;
	}

	public void setTipo(String tipo) {
		this.tipo = tipo;
	}

	@Column(name = "imputable")
	public boolean isImputable() {
		return imputable;
	}

	public void setImputable(boolean imputable) {
		this.imputable = imputable;
	}
	
	public void AgregarMovimiento(Movimiento movimiento) {
		
		if (movimiento.getTipoMovimiento().equals(TipoMovimiento.INGRESO))
		{			
			setSaldo(getSaldo() + movimiento.getImporte());
		}else 
		{
			setSaldo(getSaldo() - movimiento.getImporte());
		}
		
		movimiento.setSaldo(getSaldo());
		actualizarEstado();
		movimiento.setCuenta(this);
		getMovimientos().add(movimiento);	
	}
	
	public void actualizarEstado()
	{
		if (getSaldo() == 0D)
		{
			setEstado(Estado.SALDADA);
		}else if (getSaldo()>0)
		{
			setEstado(Estado.SALDO_ACREEDOR);
		}else {
			setEstado(Estado.SALDO_DEUDOR);
		}
	}

}
